using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Collections.Generic;
using System.Data.SqlClient;

public class Invoice : AccountItem
{
    private int invoiceId;
    private int accountId;
    private string invoiceRef;
    private string recipientRef;
    private List<InvoiceItem> itemList;
    private InvoiceType type;

    public int InvoiceId
    {
        get { return invoiceId; }
        set { invoiceId = value; }
    }

    public int AccountId
    {
        get { return accountId; }
        set { accountId = value; }
    }

    public string RecipientRef
    {
        get { return recipientRef; }
        set { recipientRef = value; }
    }

    public string InvoiceRef
    {
        get { return invoiceRef; }
        set { invoiceRef = value; }
    }

    public List<InvoiceItem> ItemList
    {
        get { return itemList; }
        set { itemList = value; }
    }

    public InvoiceType Type
    {
        get { return type; }
        set { type = value; }
    }

    /// <summary>
    /// Parameterless constructor for serialization.
    /// </summary>
    protected Invoice() { }

    public Invoice(
        int invoiceId,
        int accountId,
        string invoiceRef,
        string recipientRef,
        InvoiceType type,
        DateTime invoiceDate,
        DateTime createDate,
        DateTime updateDate)
        : base(invoiceDate, createDate, updateDate, 0)
    {
        this.invoiceId = invoiceId;
        this.accountId = accountId;
        this.invoiceRef = invoiceRef;
        this.recipientRef = recipientRef;
        this.type = type;
    }

    public Invoice(
        int invoiceId,
        int accountId,
        string invoiceRef,
        string recipientRef,
        InvoiceType type,
        DateTime invoiceDate,
        DateTime createDate,
        DateTime updateDate,
        string accountCode,
        string accountTitle)
        : this(
            invoiceId, 
            accountId, 
            invoiceRef, 
            recipientRef, 
            type, 
            invoiceDate, 
            createDate, 
            updateDate)
    {
        this.AccountCode = accountCode;
        this.AccountTitle = accountTitle;
    }

    public Invoice(
        int invoiceId,
        int accountId,
        string invoiceRef,
        string recipientRef,
        List<InvoiceItem> itemList,
        InvoiceType type,
        DateTime invoiceDate,
        DateTime createDate,
        DateTime updateDate)
        : this(
            invoiceId, 
            accountId, 
            invoiceRef, 
            recipientRef, 
            type, 
            invoiceDate, 
            createDate, 
            updateDate)
    {
        this.itemList = itemList;
    }

    internal static Invoice Create(
        string invoiceRef,
        string recipientRef,
        List<InvoiceItem> itemList,
        DateTime invoiceDate,
        InvoiceType type,
        int accountId)
    {
        int invoiceId;
        using (SqlConnection connection = new SqlConnection(Settings.ConnectionStrings.AccountsDatabase))
        {
            SqlCommand command = new SqlCommand("InvoiceCreate", connection);
            command.CommandType = CommandType.StoredProcedure;

            command.Parameters.AddWithValue("accountId", accountId);
            command.Parameters.AddWithValue("invoiceRef", invoiceRef);
            command.Parameters.AddWithValue("recipientRef", recipientRef);
            command.Parameters.AddWithValue("invoiceDate", invoiceDate);
            command.Parameters.AddWithValue("typeFlag", type);
            command.Parameters.Add("invoiceId", SqlDbType.Int).Direction = ParameterDirection.Output;

            connection.Open();
            command.ExecuteNonQuery();

            invoiceId = (int)command.Parameters["invoiceId"].Value;

            SqlCommand itemCommand = new SqlCommand("InvoiceItemCreate", connection);
            itemCommand.CommandType = CommandType.StoredProcedure;

            itemCommand.Parameters.AddWithValue("invoiceId", invoiceId);
            itemCommand.Parameters.Add("details", SqlDbType.NVarChar, 200);
            itemCommand.Parameters.Add("quantity", SqlDbType.Float);
            itemCommand.Parameters.Add("unitTypeFlag", SqlDbType.Int);
            itemCommand.Parameters.Add("rate", SqlDbType.Money);

            itemCommand.Parameters.Add("invoiceItemId", SqlDbType.Int)
                .Direction = ParameterDirection.Output;

            foreach (InvoiceItem item in itemList)
            {
                itemCommand.Parameters["details"].Value = item.Details;
                itemCommand.Parameters["quantity"].Value = item.Quantity;
                itemCommand.Parameters["unitTypeFlag"].Value = item.UnitType;
                itemCommand.Parameters["rate"].Value = item.Rate;

                itemCommand.ExecuteNonQuery();

                item.InvoiceId = invoiceId;
                item.InvoiceItemId = (int)itemCommand.Parameters["invoiceItemId"].Value;
            }

            connection.Close();
        }

        return new Invoice(
            invoiceId,
            accountId,
            invoiceRef,
            recipientRef,
            itemList,
            type,
            invoiceDate,
            DateTime.Now,
            DateTime.Now);
    }

    internal static Invoice FromReader(SqlDataReader reader)
    {
        Invoice invoice = new Invoice(
                    (int)reader["InvoiceId"],
                    (int)reader["AccountId"],
                    (string)reader["InvoiceRef"],
                    (string)reader["RecipientRef"],
                    (InvoiceType)reader["TypeFlag"],
                    (DateTime)reader["InvoiceDate"],
                    (DateTime)reader["CreateDate"],
                    (DateTime)reader["UpdateDate"],
                    (string)reader["AccountCode"],
                    (string)reader["AccountTitle"]);

        invoice.ValueAmount = (decimal)reader["Total"];

        return invoice;
    }

    internal static List<Invoice> Fetch(InvoiceType type)
    {
        List<Invoice> invoiceList = new List<Invoice>();
        using (SqlConnection connection = new SqlConnection(Settings.ConnectionStrings.AccountsDatabase))
        {
            SqlCommand command = new SqlCommand("InvoiceFetch", connection);
            command.CommandType = CommandType.StoredProcedure;
            command.Parameters.AddWithValue("typeFlag", type);

            connection.Open();

            SqlDataReader reader = command.ExecuteReader();
            while (reader.Read())
            {
                invoiceList.Add(FromReader(reader));
            }

            connection.Close();
        }
        return invoiceList;
    }

    internal static List<Invoice> Fetch(int accountId)
    {
        List<Invoice> invoiceList = new List<Invoice>();
        using (SqlConnection connection = new SqlConnection(Settings.ConnectionStrings.AccountsDatabase))
        {
            SqlCommand command = new SqlCommand("InvoiceFetchByAccountId", connection);
            command.CommandType = CommandType.StoredProcedure;
            command.Parameters.AddWithValue("accountId", accountId);

            connection.Open();

            SqlDataReader reader = command.ExecuteReader();
            while (reader.Read())
            {
                invoiceList.Add(FromReader(reader));
            }

            connection.Close();
        }
        return invoiceList;
    }
}

public enum InvoiceType
{
    Client = 1,
    Supplier = 2
}
